import gevent.monkey
# 通过对 Python 标准库代码进行 monkey patch 可以使得原来禁止在非主线程下使用的一些函数和模块变为可以在子线程中正常工作，
# 位置不能动,否则会递归调用
gevent.monkey.patch_all()

from global_config import mysql as mysql_config, blacklist, proxyIp

import os
os.environ["http_proxy"] = proxyIp
os.environ["https_proxy"] = proxyIp

import requests
import json
from models.sqlalchemy_db import db
import logging
import traceback
from os import path
import flask_compress
from flask import Flask, request, Response, g
from gevent.pywsgi import WSGIServer
from startup import load_task, load_plugin
from utils.gol import global_values
from utils.logger import root_logger
from utils.scheduler import scheduler
from utils.exceptions import CustomHTTPException

# 初始化一个新的 Flask 应用程序
app = Flask(__name__)
# 注册了一个用于自动压缩响应的扩展
flask_compress.Compress(app)

# 绑定数据库
app.config['SQLALCHEMY_BINDS'] = {
    'nuc-info': 'mysql+pymysql://{}:{}@{}:3306/nuc_info'
    .format(mysql_config['user'], mysql_config['password'], mysql_config['host'])
}

# 将 SQLAlchemy 对象初始化为一个 Flask 扩展，并将其注册到 Flask 实例中的常见方法。
# 通过这种方式，我们可以在应用程序组件之间轻松地共享 SQLAlchemy 的实例对象，并统一管理和自动更新数据库模型和连接池等资源。
db.init_app(app)

# @app.errorhandler(404)
# def page_not_found(e):
#     app.logger.warning("由于 404 重定向 %s", request.url)
#     return redirect('')


@app.errorhandler(CustomHTTPException)
def on_custom_http_exception(e: CustomHTTPException):
    g.values['code'] = e.code
    return {
        'code': e.code,
        'message': e.message
    }


@app.errorhandler(Exception)
def on_sever_error(e):
    if isinstance(e, requests.exceptions.ConnectionError):
        g.values['code'] = -1
        return {
            'code': -1,
            'message': 'VPN通道已关闭!'
        }
    if isinstance(e, requests.exceptions.MissingSchema):
        g.values['code'] = -1
        logging.error('教务系统异常!')
        return {
            'code': -1,
            'message': '教务系统开小差了，请重试!'
        }
    if isinstance(e, json.decoder.JSONDecodeError):
        g.values['code'] = -1
        logging.error('JSONDecodeError异常!')
        return {
            'code': -1,
            'message': '请稍后再试!'
        }
    logging.exception(traceback.format_exc())
    logging.error("服务器异常!")
    g.values['code'] = -1
    return {
        'code': -1,
        'message': '服务器开小差了~'
    }

def initializer():
    global_values.set_value("proxy_status_ok", True)
    # 加载plugins_v3下所有python文件
    plugins = load_plugin.load_plugins(
        # 拼接出绝对路径
        path.join(path.dirname(__file__), 'plugins_v3'),
        # 重命名后的文件夹名
        'plugins_v3'
    )
    for i in plugins:
        # 将它们注册到 Flask 实例对象中，以便应用程序能够识别和使用这些插件
        app.register_blueprint(i.api)
        # print(i.api)
    # 加载自定义定时任务
    load_task.load_tasks(
        path.join(path.dirname(__file__), 'tasks'),
        'tasks')
    # 执行定时任务
    scheduler.start()


@app.before_request
def before_request():
    if request.args.get('key') in blacklist:
        logging.warning('黑名单用户'+request.args.get('key')+'被拦截')
        return {
            'code': -1,
            'message': '您已被管理员拉黑!'
        }
    # 实例化g
    g.values = {}
    # g.values = {'time': time.time() * 1000}

#
# @app.after_request
# def log(response: Response):
#     processing_time = int(time.time() * 1000 - g.values['time'])
#     loki.log(request.url_rule,
#              processing_time,
#              g.values.get('code', 0),
#              g.values.get('cached', False),
#              request.full_path)
#     return response


if __name__ == '__main__':
    initializer()
    http_server = WSGIServer(('0.0.0.0', 8080), app, log=root_logger, error_log=root_logger)
    http_server.serve_forever()
